package com.cl.code.generate.util;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.javadoc.Javadoc;
import com.github.javaparser.javadoc.JavadocBlockTag;
import lombok.Getter;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Java注释提取工具类
 * 用于从Java源码文件中提取类、方法、字段的Javadoc注释
 *
 * @author CodeLink
 * @version 2.0
 */
public class JavaCommentExtractor {

    private static final JavaParser JAVA_PARSER = new JavaParser();

    /**
     * 提取指定类的头部注释
     *
     * @param clazz 要提取注释的类
     * @return 类的头部注释，如果没有找到则返回空字符串
     */
    public static String extractClassComment(Class<?> clazz) {
        ClassCommentInfo classInfo = extractClassCommentInfo(clazz);
        return classInfo.getComment();
    }

    /**
     * 提取指定类的完整注释信息
     *
     * @param clazz 要提取注释的类
     * @return 类的完整注释信息
     */
    public static ClassCommentInfo extractClassCommentInfo(Class<?> clazz) {
        try {
            CompilationUnit cu = getCompilationUnit(clazz);
            if (cu != null) {
                return extractClassCommentFromCompilationUnit(cu, clazz.getSimpleName());
            }
        } catch (Exception e) {
            // 忽略异常
        }
        return new ClassCommentInfo("", "", "", new HashMap<>());
    }

    /**
     * 提取指定字段的注释信息
     *
     * @param field 要提取注释的字段
     * @return 字段注释信息
     */
    public static FieldCommentInfo extractFieldComment(Field field) {
        try {
            Class<?> clazz = field.getDeclaringClass();
            CompilationUnit cu = getCompilationUnit(clazz);
            if (cu != null) {
                return extractFieldCommentFromCompilationUnit(cu, field);
            }
        } catch (Exception e) {
            // 忽略异常
        }
        return new FieldCommentInfo("", new HashMap<>());
    }

    /**
     * 提取指定方法的注释信息
     *
     * @param method 要提取注释的方法
     * @return 方法注释信息，包含方法描述、参数注释和返回值注释
     */
    public static MethodCommentInfo extractMethodComment(Method method) {
        try {
            Class<?> clazz = method.getDeclaringClass();
            CompilationUnit cu = getCompilationUnit(clazz);
            if (cu != null) {
                return extractMethodCommentFromCompilationUnit(cu, method);
            }
        } catch (Exception e) {
            // 忽略异常
        }
        return new MethodCommentInfo("", new HashMap<>(), "");
    }

    /**
     * 获取类的编译单元
     *
     * @param clazz 类
     * @return 编译单元
     */
    private static CompilationUnit getCompilationUnit(Class<?> clazz) {
        try {
            String sourceFileName = clazz.getSimpleName() + ".java";
            String packagePath = clazz.getPackage().getName().replace('.', '/');

            // 尝试多个可能的源文件路径
            String[] possiblePaths = {
                    "src/main/java/" + packagePath + "/" + sourceFileName,
                    "src/test/java/" + packagePath + "/" + sourceFileName,
                    packagePath + "/" + sourceFileName
            };

            // 尝试从文件系统读取
            for (String pathStr : possiblePaths) {
                CompilationUnit cu = tryParseFromPath(pathStr);
                if (cu != null) return cu;

                // 尝试从当前工作目录开始查找
                Path fullPath = Paths.get(System.getProperty("user.dir")).resolve(pathStr);
                cu = tryParseFromPath(fullPath.toString());
                if (cu != null) return cu;
            }

            // 尝试从类路径资源中读取
            String resourcePath = packagePath + "/" + sourceFileName;
            InputStream inputStream = clazz.getClassLoader().getResourceAsStream(resourcePath);
            if (inputStream != null) {
                Optional<CompilationUnit> parseResult = JAVA_PARSER.parse(inputStream).getResult();
                if (parseResult.isPresent()) {
                    return parseResult.get();
                }
            }
        } catch (Exception e) {
            // 忽略异常
        }
        return null;
    }

    /**
     * 尝试从指定路径解析Java文件
     *
     * @param pathStr 文件路径
     * @return 编译单元，解析失败返回null
     */
    private static CompilationUnit tryParseFromPath(String pathStr) {
        try {
            Path sourcePath = Paths.get(pathStr);
            if (Files.exists(sourcePath)) {
                Optional<CompilationUnit> parseResult = JAVA_PARSER.parse(sourcePath).getResult();
                if (parseResult.isPresent()) {
                    return parseResult.get();
                }
            }
        } catch (Exception e) {
            // 忽略异常
        }
        return null;
    }

    /**
     * 从编译单元中提取类注释
     *
     * @param cu        编译单元
     * @param className 类名
     * @return 类注释信息
     */
    private static ClassCommentInfo extractClassCommentFromCompilationUnit(CompilationUnit cu, String className) {
        Optional<ClassOrInterfaceDeclaration> classDeclaration = findClassDeclaration(cu, className);

        if (classDeclaration.isPresent()) {
            ClassOrInterfaceDeclaration clsDecl = classDeclaration.get();
            Optional<JavadocComment> javadoc = clsDecl.getJavadocComment();
            if (javadoc.isPresent()) {
                return parseClassJavadoc(javadoc.get());
            }
        }

        return new ClassCommentInfo("", "", "", new HashMap<>());
    }

    /**
     * 从编译单元中提取方法注释
     *
     * @param cu     编译单元
     * @param method 方法
     * @return 方法注释信息
     */
    private static MethodCommentInfo extractMethodCommentFromCompilationUnit(CompilationUnit cu, Method method) {
        String className = method.getDeclaringClass().getSimpleName();
        Optional<ClassOrInterfaceDeclaration> classDeclaration = findClassDeclaration(cu, className);

        if (classDeclaration.isPresent()) {
            List<MethodDeclaration> methods = classDeclaration.get().findAll(MethodDeclaration.class);
            for (MethodDeclaration methodDecl : methods) {
                if (isMethodMatch(methodDecl, method)) {
                    return extractMethodCommentInfo(methodDecl);
                }
            }
        }

        return new MethodCommentInfo("", new HashMap<>(), "");
    }

    /**
     * 从编译单元中提取字段注释
     *
     * @param cu    编译单元
     * @param field 字段
     * @return 字段注释信息
     */
    private static FieldCommentInfo extractFieldCommentFromCompilationUnit(CompilationUnit cu, Field field) {
        String className = field.getDeclaringClass().getSimpleName();
        Optional<ClassOrInterfaceDeclaration> classDeclaration = findClassDeclaration(cu, className);

        if (classDeclaration.isPresent()) {
            List<FieldDeclaration> fields = classDeclaration.get().findAll(FieldDeclaration.class);
            for (FieldDeclaration fieldDecl : fields) {
                for (VariableDeclarator variable : fieldDecl.getVariables()) {
                    if (variable.getNameAsString().equals(field.getName())) {
                        return extractFieldCommentInfo(fieldDecl);
                    }
                }
            }
        }

        return new FieldCommentInfo("", new HashMap<>());
    }

    /**
     * 查找类声明
     *
     * @param cu        编译单元
     * @param className 类名
     * @return 类声明
     */
    private static Optional<ClassOrInterfaceDeclaration> findClassDeclaration(CompilationUnit cu, String className) {
        return cu.findFirst(ClassOrInterfaceDeclaration.class,
                cls -> cls.getNameAsString().equals(className));
    }

    /**
     * 判断方法声明是否匹配反射方法
     *
     * @param methodDecl 方法声明
     * @param method     反射方法
     * @return 是否匹配
     */
    private static boolean isMethodMatch(MethodDeclaration methodDecl, Method method) {
        // 比较方法名
        if (!methodDecl.getNameAsString().equals(method.getName())) {
            return false;
        }

        // 比较参数数量
        if (methodDecl.getParameters().size() != method.getParameterCount()) {
            return false;
        }

        // 比较参数类型（简单比较，可能需要更复杂的类型匹配逻辑）
        Class<?>[] paramTypes = method.getParameterTypes();
        for (int i = 0; i < paramTypes.length; i++) {
            Parameter param = methodDecl.getParameter(i);
            String paramTypeName = param.getType().asString();
            String expectedTypeName = paramTypes[i].getSimpleName();

            // 简单的类型名比较
            if (!paramTypeName.equals(expectedTypeName) &&
                    !paramTypeName.equals(paramTypes[i].getName()) &&
                    !paramTypeName.endsWith("." + expectedTypeName)) {
                return false;
            }
        }

        return true;
    }

    /**
     * 解析类的Javadoc注释
     *
     * @param javadocComment Javadoc注释
     * @return 类注释信息
     */
    private static ClassCommentInfo parseClassJavadoc(JavadocComment javadocComment) {
        Javadoc javadoc = javadocComment.parse();

        String description = javadoc.getDescription().toText().trim();

        Map<String, String> tags = new HashMap<>();
        String author = "";
        String version = "";

        for (JavadocBlockTag tag : javadoc.getBlockTags()) {
            String tagName = tag.getType().name().toLowerCase();
            String tagContent = tag.getContent().toText().trim();

            if ("author".equals(tagName)) {
                author = tagContent;
            } else if ("version".equals(tagName)) {
                version = tagContent;
            } else {
                tags.put(tagName, tagContent);
            }
        }

        return new ClassCommentInfo(description, author, version, tags);
    }

    /**
     * 提取方法注释信息
     *
     * @param methodDecl 方法声明
     * @return 方法注释信息
     */
    private static MethodCommentInfo extractMethodCommentInfo(MethodDeclaration methodDecl) {
        Optional<JavadocComment> javadocOpt = methodDecl.getJavadocComment();
        if (javadocOpt.isEmpty()) {
            return new MethodCommentInfo("", new HashMap<>(), "");
        }

        Javadoc javadoc = javadocOpt.get().parse();
        String description = javadoc.getDescription().toText().trim();

        Map<String, String> paramComments = extractParamComments(javadoc);
        String returnComment = extractReturnComment(javadoc);

        return new MethodCommentInfo(description, paramComments, returnComment);
    }

    /**
     * 提取字段注释信息
     *
     * @param fieldDecl 字段声明
     * @return 字段注释信息
     */
    private static FieldCommentInfo extractFieldCommentInfo(FieldDeclaration fieldDecl) {
        Optional<JavadocComment> javadocOpt = fieldDecl.getJavadocComment();
        if (javadocOpt.isEmpty()) {
            return new FieldCommentInfo("", new HashMap<>());
        }

        Javadoc javadoc = javadocOpt.get().parse();
        String description = javadoc.getDescription().toText().trim();

        Map<String, String> tags = new HashMap<>();
        for (JavadocBlockTag tag : javadoc.getBlockTags()) {
            String tagName = tag.getType().name().toLowerCase();
            String tagContent = tag.getContent().toText().trim();
            tags.put(tagName, tagContent);
        }

        return new FieldCommentInfo(description, tags);
    }

    /**
     * 提取参数注释
     *
     * @param javadoc Javadoc对象
     * @return 参数注释映射
     */
    private static Map<String, String> extractParamComments(Javadoc javadoc) {
        return javadoc.getBlockTags().stream()
                .filter(tag -> tag.getType() == JavadocBlockTag.Type.PARAM)
                .filter(tag -> tag.getName().isPresent())
                .collect(Collectors.toMap(
                        tag -> tag.getName().get(),
                        tag -> tag.getContent().toText().trim(),
                        (existing, replacement) -> existing
                ));
    }

    /**
     * 提取返回值注释
     *
     * @param javadoc Javadoc对象
     * @return 返回值注释
     */
    private static String extractReturnComment(Javadoc javadoc) {
        return javadoc.getBlockTags().stream()
                .filter(tag -> tag.getType() == JavadocBlockTag.Type.RETURN)
                .findFirst()
                .map(tag -> tag.getContent().toText().trim())
                .orElse("");
    }

    /**
     * 类注释信息类
     */
    @Getter
    public static class ClassCommentInfo {
        private final String comment;
        private final String author;
        private final String version;
        private final Map<String, String> tags;

        public ClassCommentInfo(String comment, String author, String version, Map<String, String> tags) {
            this.comment = comment;
            this.author = author;
            this.version = version;
            this.tags = tags;
        }

        public String getTag(String tagName) {
            return tags.getOrDefault(tagName, "");
        }

    }

    /**
     * 方法注释信息类
     */
    @Getter
    public static class MethodCommentInfo {
        private final String comment;
        private final Map<String, String> paramComments;
        private final String returnComment;

        public MethodCommentInfo(String comment, Map<String, String> paramComments, String returnComment) {
            this.comment = comment;
            this.paramComments = paramComments;
            this.returnComment = returnComment;
        }

        public String getParamComment(String paramName) {
            return paramComments.getOrDefault(paramName, "");
        }

    }

    /**
     * 字段注释信息类
     */
    @Getter
    public static class FieldCommentInfo {
        private final String comment;
        private final Map<String, String> tags;

        public FieldCommentInfo(String comment, Map<String, String> tags) {
            this.comment = comment;
            this.tags = tags;
        }

        public String getTag(String tagName) {
            return tags.getOrDefault(tagName, "");
        }

    }
}